# -* - coding: UTF-8 -* -
#import sys 
#reload(sys)
#sys.setdefaultencoding('utf8')
#V2.1 by Asun
#2019-02-01
import socket,string
import time 
from time import sleep
import glob, os,sys
import logging,signal
from base_thread import Thread
from config import Config
from controller import *
from service_center import *
#导入服务端(Redis|RabbitMQ)和客户端(fastcgi|http)
app_path = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(app_path,'Server'))
sys.path.append(os.path.join(app_path,'Client'))
from Client.factory import *
from Server.factory import *

#导入工厂
sys.path.append(os.path.join(app_path,'Factory'))
from Factory.rpc_factory import *
from Factory.worker_factory import *
from Factory.notify_factory import *


#导入中心
sys.path.append(os.path.join(app_path,'Center'))
from Center.command_center import *
from Center.sql_center import *
from Center.manage_center import *
from Center.server_center import *
from Center.notify_center import *


	
#动态创建线程
class CoopNode(object):
	def __init__(self,coop,config,node_id): 
		self.coop=coop	
		self.config=config
		self.node_id=node_id
		
		self.service_center=self.coop.service_center
		self.notify_center=self.coop.notify_center
		self.sql_center=self.coop.sql_center
		self.cmd_center=self.coop.cmd_center
		#设置数据路径
		self.data_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'data')
		if not os.path.isdir(self.data_path):
			os.mkdir(self.data_path)
			
		
		self.QueueDriver=self.config.get('queue_server','driver','redis')
		
		self.server_factory= ServerFactory(self.QueueDriver)
		self.client_factory = ClientFactory('fastcgi')
		
		#消息队列
		self.worker_factory = {}
		worker_names = self.config.get('queue_server','queue_name','default').split(',')
		for worker_name in worker_names:
			#logging.info("Create Woker:"+worker_name)
			worker_count=self.config.get_int(worker_name,'client_count',self.config.get_int('coop','client_count',1))
			self.worker_factory[worker_name] = WorkerFactory(self.node_id,self.data_path,worker_name,worker_count,self.server_factory,self.client_factory,self.notify_center,self.service_center,self.config)
		

		#RPC队列
		self.rpc_factory = RpcFactory(self.server_factory,self.client_factory,self.service_center,self.config)
		
		#通知队列	
		self.notify_factory = NotifyFactory(self.server_factory,self.client_factory,self.service_center,self.config)
		
			
	def start(self):
		for name in self.worker_factory:
			self.worker_factory[name].start()	
		self.rpc_factory.start()
		self.notify_factory.start()	
			
	def stop(self):
		for name in self.worker_factory:
			self.worker_factory[name].stop()	
			
		self.rpc_factory.stop()
			
		self.notify_factory.stop()
		
		logging.info("All Thread Stoped!")	

		logging.info("Thread Save!")
	def terminate(self):
		logging.info("Queue Thread Terminate!")
		for name in self.worker_factory:
			self.worker_factory[name].terminate()
		
		logging.info("RPC Thread Terminate!")	
		self.rpc_factory.terminate()
		
		logging.info("Notify Thread Terminate!")	
		self.notify_factory.terminate()

	
		logging.info("All Thread Terminate!")	
			

		
class Coop(object):
	
	is_master = True
	
	def __init__(self):
		self.started=False
		self.nodes=[]
		self.server_list = []
		self.server_center = False
		self.build_env()
		self.build_thread()
		
	def build_env(self):
		import logging.config
		from day_handler import DayFileHandler
		
		#配置日志
		log_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'log')
		
		if not os.path.isdir(log_path):
			os.mkdir(log_path)
			
		
		conf_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'logger.conf')
		if os.path.isfile(conf_path):
			logging.config.fileConfig(conf_path)
		else:
			logging.basicConfig(level=logging.DEBUG, filemode = 'a')
		formatter = logging.Formatter('%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s')   # 每行日志的前缀设置
		fileTimeHandler = DayFileHandler(os.path.join(log_path,'run.log'), "MIDNIGHT", 1, 30)
		fileTimeHandler.setFormatter(formatter)
		logging.getLogger().addHandler(fileTimeHandler)
		
		self.service_center=ServiceCenter()
		
		#读取配置文件
		conf_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'coop.conf')
		self.config=Config(conf_path)
		data_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'data')
		if not os.path.isdir(data_path):
			os.mkdir(data_path)

			
		self.sql_center=SqlCenter(os.path.join(data_path,"commands.txt"))
		
		
		self.server_list = self.config.get('coop','server_list','127.0.0.1').split(',')
		self.master_server = self.config.get('coop','master_server',self.server_list[0]).split(',')
		
		#命令中心
		self.cmd_center=CommandCenter(self.service_center,self.config,self.server_list)
		
		
		#通知事件
		self.notify_center=NotifyCenter(os.path.join(data_path,"notifies.txt"))
		
		#管理中心
		self.QueueDriver=self.config.get('queue_server','driver','redis')
		
		self.server_factory= ServerFactory(self.QueueDriver)
		
	def create_server(self,name):
		if not self.server_center:
			self.server_center = ServerCenter(self,self.server_factory,self.service_center,self.config)
			self.server_center.create(name)
			self.server_center.start()
			
	#创建线程列表，线程中将创建对应的进程
	def build_thread(self):

		self.ctrl=Socket(self,self.cmd_center)
		
		self.server=Server(self)
		
		self.manage_center=ManageCenter(self,self.server_factory,self.service_center,self.config)
				
		self.nodes=[]
		for i in range(self.config.get_int('coop','node_count',1)):#10线程执行
			t = CoopNode(self,self.config,i)  
			self.nodes.append(t)			

		
	def start(self):
		logging.info(self.nodes)
		#读取SQL命令
		self.sql_center.load()
		self.notify_center.load()
		self.cmd_center.start()
		self.manage_center.start()
		self.server.start()
		
		self.service_center.start()
		
		self.started=True
		for t in self.nodes:
			t.start()
		logging.info('已启动')

	def send_quit(self):
		logging.info('发送退出命令')
		address = ('127.0.0.1',9981)
		s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
		s.sendto(b"quit", address)
		s.close()
		
	def set_master_manage(self):
		print('发送设置主管命令',self.master_server,self.server_list)
		#最后一台为主管
		s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

		for ip in self.server_list:
			if not (ip in self.master_server):#将不是主管的停掉
				print('关闭管理',ip)
				address = (ip,9981)#
				s.sendto(b"stop_manage", address)
		for ip in self.server_list:
			print('关闭管理',ip)
			address = (ip,9981)#
			cmd = "create "+ip
			s.sendto(bytes(cmd.encode('utf-8')), address)
				
		s.close()
		
	def stop(self):
		self.server.stop()
		for t in self.nodes:
			t.stop()
		#保存SQL命令
		self.service_center.stop()
		
		self.cmd_center.stop()
		
		self.sql_center.save()
		
		self.manage_center.stop()
		
		if self.server_center:
			self.server_center.stop()
		
		self.notify_center.save()
		return True
		
	def run(self):

		logging.info('coop start')
		
		self.start()
		
		#设置主管
		timer = threading.Timer(5, self.set_master_manage)
		timer.start() 

		try:
			self.ctrl.start()#阻塞模式	
		except Exception as e:
			logging.error('run error:')
			logging.exception(e)
			
		logging.info('coop stop')
		
	def terminate(self):
		if not self.started:
			self.send_quit()
			time.sleep(1)
			return False
		else:
			self.stop()
			for t in self.nodes:
				t.terminate()
			
			time.sleep(2)
			logging.info('All Node terminate')

			self.manage_center.terminate()
			logging.info('manage_center Terminate')
	
			self.cmd_center.terminate()
			logging.info('cmd_center Terminate')
			
			logging.info('Controller Stop')
			self.ctrl.stop()
			
			logging.info('Coop Terminated')
			